﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Data;
using System.Windows.Interactivity;
using System.ComponentModel;
using System.Collections.Generic;

namespace MoneyBook.Windows.Data {

    public class CollectionViewSourceBinder : DependencyObject, IAttachable {

        public CollectionViewSource CollectionViewSource {
            get { return (CollectionViewSource)GetValue(CollectionViewSourceProperty); }
            set { SetValue(CollectionViewSourceProperty, value); }
        }

        public static readonly DependencyProperty CollectionViewSourceProperty =
            DependencyProperty.Register("CollectionViewSource", typeof(CollectionViewSource),
            typeof(CollectionViewSourceBinder),
            new PropertyMetadata(OnCollectionViewSourceChanged));

        private static void OnCollectionViewSourceChanged(object sender, DependencyPropertyChangedEventArgs e) {
            CollectionViewSourceBinder self = sender as CollectionViewSourceBinder;
            if (self != null) {
                self.OnCollectionViewSourceChanged(e.NewValue as CollectionViewSource, e.OldValue as CollectionViewSource);
            }
        }

        private void OnCollectionViewSourceChanged(CollectionViewSource newValue, CollectionViewSource oldValue) {
            if (oldValue != null) {
                oldValue.ClearValue(CollectionViewSource.SourceProperty);
            }
            if (newValue == null) {
                return;
            }

            newValue.Source = this.Source;
            using (newValue.DeferRefresh()) {
                if (this.SortDescriptions != null) {
                    newValue.SortDescriptions.Clear();
                    foreach (SortDescription sort in this.SortDescriptions) {
                        newValue.SortDescriptions.Add(sort);
                    }
                }
                if(this.GroupDescriptions != null){
                    newValue.GroupDescriptions.Clear();
                    foreach (GroupDescription group in this.GroupDescriptions) {
                        newValue.GroupDescriptions.Add(group);
                    }
                }
            }
        }

        public object Source {
            get { return (object)GetValue(SourceProperty); }
            set { SetValue(SourceProperty, value); }
        }

        public static readonly DependencyProperty SourceProperty =
            DependencyProperty.Register("Source", typeof(object), typeof(CollectionViewSourceBinder),
            new PropertyMetadata(OnSourceChanged));

        private static void OnSourceChanged(object sender, DependencyPropertyChangedEventArgs e) {
            CollectionViewSourceBinder self = sender as CollectionViewSourceBinder;
            if (self != null) {
                self.OnSourceChanged(e.NewValue, e.OldValue);
            }
        }

        private void OnSourceChanged(object newValue, object oldValue) {
            if (this.CollectionViewSource != null) {
                this.CollectionViewSource.Source = this.Source;
            }
        }

        public SortDescriptionCollection SortDescriptions {
            get { return (SortDescriptionCollection)GetValue(SortDescriptionsProperty); }
            set { SetValue(SortDescriptionsProperty, value); }
        }

        public static readonly DependencyProperty SortDescriptionsProperty =
            DependencyProperty.Register("SortDescriptions", typeof(SortDescriptionCollection),
            typeof(CollectionViewSourceBinder), new PropertyMetadata(OnSortDescriptionsChanged));

        private static void OnSortDescriptionsChanged(object sender, DependencyPropertyChangedEventArgs e) {
            CollectionViewSourceBinder self = sender as CollectionViewSourceBinder;
            if (self != null) {
                self.OnSortDescriptionsChanged(e.NewValue as SortDescriptionCollection, e.OldValue as SortDescriptionCollection);
            }
        }

        private void OnSortDescriptionsChanged(SortDescriptionCollection newValue, SortDescriptionCollection oldValue) {
            if (this.CollectionViewSource != null) {
                using (this.CollectionViewSource.DeferRefresh()) {
                    this.CollectionViewSource.SortDescriptions.Clear();
                    if (newValue != null) {
                        foreach (SortDescription sort in newValue) {
                            this.CollectionViewSource.SortDescriptions.Add(sort);
                        }
                    }
                }
            }
        }

        public IEnumerable<GroupDescription> GroupDescriptions {
            get { return (IEnumerable<GroupDescription>)GetValue(GroupDescriptionsProperty); }
            set { SetValue(GroupDescriptionsProperty, value); }
        }

        public static readonly DependencyProperty GroupDescriptionsProperty =
            DependencyProperty.Register("GroupDescriptions", typeof(IEnumerable<GroupDescription>),
            typeof(CollectionViewSourceBinder), new PropertyMetadata(OnGroupDescriptionsChanged));

        private static void OnGroupDescriptionsChanged(object sender, DependencyPropertyChangedEventArgs e) {
            CollectionViewSourceBinder self = sender as CollectionViewSourceBinder;
            if (self != null) {
                self.OnGroupDescriptionsChanged(e.NewValue as IEnumerable<GroupDescription>,
                    e.OldValue as IEnumerable<GroupDescription>);
            }
        }

        private void OnGroupDescriptionsChanged(IEnumerable<GroupDescription> newValue, IEnumerable<GroupDescription> oldValue) {
            if (this.CollectionViewSource != null) {
                using (this.CollectionViewSource.DeferRefresh()) {
                    this.CollectionViewSource.GroupDescriptions.Clear();
                    if (newValue != null) {
                        foreach (GroupDescription groupDescription in newValue) {
                            this.CollectionViewSource.GroupDescriptions.Add(groupDescription);
                        }
                    }
                }
            }
        }

        public void Attach(DependencyObject dependencyObject) {
            this.AssociatedObject = dependencyObject;
        }

        public void Detach() {
            this.AssociatedObject = null;
            if (this.CollectionViewSource != null) {
                this.CollectionViewSource.ClearValue(CollectionViewSource.SourceProperty);
            }
        }

        DependencyObject IAttachable.AssociatedObject {
            get {
                return this.AssociatedObject;
            }
        }

        private DependencyObject AssociatedObject { get; set; }

    }
}
